package com.example.multithread;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

class Account4 {
    private String name;
    private int asset;
    private StampedLock stampedLock = new StampedLock();

    public Account4(String name, int asset) {
        this.name = name;
        this.asset = asset;
    }

    public void save(int asset) {
        long stamp = this.stampedLock.writeLock();
        try {
            long writeStamp = this.stampedLock.tryConvertToWriteLock(stamp);
            boolean flag = true;
            while (flag) {
                if (writeStamp != 0L) {
                    stamp = writeStamp;
                    this.asset += asset;
                    TimeUnit.SECONDS.sleep(1);
                    System.out.printf("【%s】修改银行资产，当前的资产为: %10.2f%n", Thread.currentThread().getName(), this.asset / 100.0);
                    flag = false;
                } else {
                    this.stampedLock.unlockRead(stamp);
                    writeStamp = this.stampedLock.writeLock();
                    stamp = writeStamp;
                }
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            this.stampedLock.unlockWrite(stamp);
        }
    }

    @Override
    public String toString() {
        long stamp = this.stampedLock.tryOptimisticRead();
        try {
            int current = this.asset;
            TimeUnit.SECONDS.sleep(1);
            if (!this.stampedLock.validate(stamp)) {
                stamp = this.stampedLock.readLock();
                try {
                    current = this.asset;
                } finally {
                    this.stampedLock.unlockRead(stamp);
                }
            }
            return String.format("【%s】账户名称: %s，账户余额: %10.2f %n", Thread.currentThread().getName(), this.name, current / 100.0);
        } catch (InterruptedException e) {
            return null;
        }
    }
}

/**
 * 乐观锁
 */
public class StampedLockTest2 {
    public static void main(String[] args) {
        Account4 account = new Account4("杨德军", 0);
        int money[] = new int[]{110, 230, 10_000};
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                System.out.println(account);
            }, "取款线程-" + i).start();
        }
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                for (int j = 0; j < money.length; j++) {
                    account.save(money[j]);
                }
            }, "存款线程-" + i).start();
        }
    }
}
